---
title: 컴포넌트
description: .astro 컴포넌트 구문에 대한 소개입니다.
i18nReady: true
---

**Astro 컴포넌트**는 모든 Astro 프로젝트의 기본 구성 요소입니다. 이는 클라이언트 측 런타임이 없는 HTML 전용 템플릿 컴포넌트입니다. Astro 컴포넌트는 `.astro` 파일 확장자를 사용합니다.

Astro 컴포넌트는 매우 유연합니다. Astro 컴포넌트에는 헤더나 프로필 카드와 같은 **페이지에서 재사용 가능한 UI**가 포함되는 경우가 많습니다. 때로는 Astro 컴포넌트에 SEO 작업을 쉽게 만들어주는 일반적인 `<meta>` 태그 모음과 같은 작은 HTML 조각이 포함될 수도 있습니다. Astro 컴포넌트에는 전체 페이지 레이아웃이 포함될 수도 있습니다.

Astro 컴포넌트에 대해 알아야 할 가장 중요한 점은 **클라이언트에서 렌더링되지 않는다**는 것입니다. 기본적으로 빌드 시 HTML로 렌더링되며, [서버 측 렌더링 (SSR)](/ko/guides/server-side-rendering/)을 사용하는 경우 사용자의 요청을 받았을 때 HTML로 렌더링 됩니다. 컴포넌트 프런트매터에 JavaScript 코드를 포함할 수 있으며, 모든 내용은 사용자 브라우저로 전송되는 최종 페이지에서 제거됩니다. 그 결과 기본적으로 JavaScript가 추가되지 않아 사이트가 더 빨라집니다.

Astro 컴포넌트가 클라이언트 측에서 상호작용을 해야하는 경우, Astro 컴포넌트에 [표준 HTML `<script>` 태그](/ko/guides/client-side-scripts/)를 추가하거나, [UI 프레임워크 컴포넌트](/ko/guides/framework-components/#인터랙티브-컴포넌트-하이드레이션하기)를 사용할 수 있습니다.

## 컴포넌트 구조

Astro 컴포넌트는 **컴포넌트 스크립트**와 **컴포넌트 템플릿**이라는 두 가지 주요 부분으로 구성됩니다. 각 부분은 서로 다른 작업을 수행하지만 사용하기 쉽고 만들려고 하는 모든 것을 처리할 수 있는 프레임워크를 제공합니다.

```astro title="src/components/EmptyComponent.astro"
---
// 컴포넌트 스크립트 (JavaScript)
---

<!-- 컴포넌트 템플릿 (HTML + JS 표현식) -->
```

### 컴포넌트 스크립트

Astro는 코드 펜스(`---`)를 사용하여 Astro 컴포넌트에서 컴포넌트 스크립트를 식별합니다. 이전에 Markdown을 작성해 본 적이 있다면 이미 *프런트매터*라는 유사한 개념에 익숙할 것입니다. Astro의 컴포넌트 스크립트는 이 개념에서 직접적으로 영감을 받았습니다.

컴포넌트 스크립트를 사용하여 템플릿을 렌더링하는 데 필요한 JavaScript 코드를 작성할 수 있습니다. 여기에는 다음이 포함될 수 있습니다.

- 다른 Astro 컴포넌트 가져오기
- React와 같은 다른 프레임워크 컴포넌트 가져오기
- JSON 파일과 같은 데이터 가져오기
- API 또는 데이터베이스에서 콘텐츠 가져오기
- 템플릿에서 참조할 변수 생성

```astro title="src/components/MyComponent.astro"
---
import SomeAstroComponent from '../components/SomeAstroComponent.astro';
import SomeReactComponent from '../components/SomeReactComponent.jsx';
import someData from '../data/pokemon.json';

// `<X title="안녕하세요!" />`와 같이 컴포넌트에 전달된 props를 사용할 수 있습니다.
const { title } = Astro.props;
// 비공개 API나 데이터베이스에서도 외부 데이터를 가져올 수 있습니다.
const data = await fetch('SOME_SECRET_API_URL/users').then((r) => r.json());
---

<!-- 템플릿 -->
```

코드 펜스는 작성하는 JavaScript가 "펜스"되어 있음을 보장하도록 설계되었습니다. 이는 프런트엔드 애플리케이션으로 빠져나가거나 사용자의 손에 들어가지 않습니다. 데이터가 사용자의 브라우저로 전송되지 않으므로 이 공간에 비용이 많이 들거나 비공개 데이터베이스 호출과 같은 민감한 코드를 작성할 수 있습니다.

:::tip
컴포넌트 스크립트에서 TypeScript를 작성할 수도 있습니다!
:::

### 컴포넌트 템플릿

컴포넌트 템플릿은 코드 펜스 아래에 있으며 컴포넌트의 HTML 출력을 결정합니다.

여기에 일반 HTML을 작성하면 컴포넌트는 Astro 페이지에 HTML을 그대로 렌더링합니다.

[Astro 컴포넌트 템플릿 구문](/ko/basics/astro-syntax/)은 `JavaScript 표현식`, Astro [`<style>`](/ko/guides/styling/#astro에서-스타일링하기), [`<script>`](/ko/guides/client-side-scripts/#astro에서-script-사용하기) 태그, **가져온 컴포넌트**, [**특별한 Astro 지시어**](/ko/reference/directives-reference/)를 지원합니다. 컴포넌트 템플릿에서 컴포넌트 스크립트에 정의된 데이터와 값을 사용하여 동적으로 생성된 HTML을 만들 수 있습니다.

```astro title="src/components/MyFavoritePokemon.astro"
---
// 컴포넌트 스크립트
import Banner from '../components/Banner.astro';
import ReactPokemonComponent from '../components/ReactPokemonComponent.jsx';
const myFavoritePokemon = [
  /* ... */
];
const { title } = Astro.props;
---

<!-- HTML 주석이 지원됩니다! -->{/* JS 주석도 지원됩니다! */}

<Banner />
<h1>안녕하세요!</h1>

<!-- 컴포넌트 스크립트의 props 및 기타 변수를 사용합니다. -->
<p>{title}</p>

<!-- 수화를 위해 `client:` 지시어를 사용하여 다른 UI 프레임워크 컴포넌트를 렌더링합니다. -->
<ReactPokemonComponent client:visible />

<!-- JSX와 유사하게 HTML과 JavaScript 표현식을 혼합합니다. -->
<ul>
  {myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>

<!-- 템플릿 지시어를 사용하여 여러 문자열이나 객체로부터 클래스 이름을 만드세요! -->
<p class:list={['add', 'dynamic', { classNames: true }]}></p>
```

## 컴포넌트 기반 설계

컴포넌트는 **재사용 가능**하고 **구성 가능**하도록 설계되었습니다. 다른 컴포넌트 내부에서 컴포넌트를 사용하여 더 복잡한 UI를 만들 수도 있습니다. 예를 들어 `Button` 컴포넌트를 사용하여 `ButtonGroup` 컴포넌트를 만들 수 있습니다.

```astro title="src/components/ButtonGroup.astro"
---
import Button from './Button.astro';
---

<div>
  <Button title="Button 1" />
  <Button title="Button 2" />
  <Button title="Button 3" />
</div>
```

## 컴포넌트 Props

Astro 컴포넌트는 props를 정의하고 허용할 수 있습니다. 그리고 이러한 props는 HTML 렌더링을 위한 컴포넌트 템플릿에서 사용할 수 있게 됩니다. Props는 프런트매터 스크립트의 `Astro.props`에서 사용할 수 있습니다.

다음은 `greeting` prop과 `name` prop을 받는 컴포넌트의 예입니다. 전달받을 props는 전역 `Astro.props` 객체에서 구조 분해 할당됩니다.

```astro "Astro.props"
---
// src/components/GreetingHeadline.astro
// 사용: <GreetingHeadline greeting="Howdy" name="Partner" />
const { greeting, name } = Astro.props;
---

<h2>{greeting}, {name}!</h2>
```

이 컴포넌트는 다른 Astro 컴포넌트, 레이아웃, 페이지에서 가져와 렌더링될 때 props를 전달할 수 있습니다.

```astro /(\w+)=\S+/
---
// src/components/GreetingCard.astro
import GreetingHeadline from './GreetingHeadline.astro';
const name = 'Astro';
---

<h1>인사 카드</h1>
<GreetingHeadline greeting="Hi" name={name} />
<p>좋은 하루 보내세요!</p>
```

TypeScript에서 `Props` 타입 인터페이스를 사용해 props를 정의할 수도 있습니다. Astro는 프런트매터에서 `Props` 인터페이스를 선택하고 타입 경고/오류를 제공합니다. 이 props는 `Astro.props`에서 구조 분해 할당될 때 기본값을 설정할 수도 있습니다.

```astro ins={3-6}
---
// src/components/GreetingHeadline.astro
interface Props {
  name: string;
  greeting?: string;
}

const { greeting = '안녕하세요', name } = Astro.props;
---

<h2>{greeting}, {name}!</h2>
```

컴포넌트 props에 아무 값도 전달하지 않으면 기본값이 사용됩니다.

```astro ins="= "Hello"" ins="= "Astronaut""
---
// src/components/GreetingHeadline.astro
const { greeting = '안녕하세요', name = 'Astronaut' } = Astro.props;
---

<h2>{greeting}, {name}!</h2>
```

## 슬롯

`<slot />` 요소는 외부 HTML 콘텐츠를 위한 별도의 공간으로, 다른 파일의 하위 요소를 컴포넌트 템플릿에 삽입(또는 "슬롯")할 수 있습니다.

기본적으로 컴포넌트에 전달된 모든 하위 요소는 `<slot />`에 렌더링됩니다.

:::note
Astro 컴포넌트에 전달되어 `Astro.props`를 통해 컴포넌트 전체에서 사용할 수 있는 속성인 _props_ 와는 달리, _slots_ 는 하위 HTML 요소를 렌더링합니다.
:::

```astro "<slot />"
---
// src/components/Wrapper.astro
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props;
---

<div id="content-wrapper">
  <Header />
  <Logo />
  <h1>{title}</h1>
  <slot />
  <!-- 하위 요소 렌더링 -->
  <Footer />
</div>
```

```astro {6-7}
---
// src/pages/fred.astro
import Wrapper from '../components/Wrapper.astro';
---

<Wrapper title="Fred's Page">
  <h2>Fred에 대한 모든 것</h2>
  <p>다음은 Fred에 관한 내용입니다.</p>
</Wrapper>
```

이 패턴은 [Astro 레이아웃 컴포넌트](/ko/basics/layouts/)의 기초입니다. HTML 콘텐츠의 전체 페이지는 `<SomeLayoutComponent></SomeLayoutComponent>` 태그로 감싸져 공통 페이지 요소 내에서 렌더링되기 위해 컴포넌트로 전달될 수 있습니다.

### 명명된 슬롯

Astro 컴포넌트에는 명명된 슬롯이 있을 수도 있습니다. 이를 통해 특정 슬롯의 이름을 가진 HTML 요소만 해당 슬롯의 위치로 전달할 수 있습니다.

슬롯의 이름은 `name` 속성을 사용하여 지정됩니다.

```astro /<slot .*?/>/
---
// src/components/Wrapper.astro
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props;
---

<div id="content-wrapper">
  <Header />
  <slot name="after-header" />
  <!--  `slot="after-header"` 속성을 가진 하위 요소가 여기에 전달됩니다. -->
  <Logo />
  <h1>{title}</h1>
  <slot />
  <!--  `slot`이 없거나 `slot="default"` 속성을 가진 하위 요소가 여기에 전달됩니다. -->
  <Footer />
  <slot name="after-footer" />
  <!--  `slot="after-footer"` 속성을 가진 하위 요소가 여기에 전달됩니다. -->
</div>
```

특정 슬롯에 HTML 콘텐츠를 삽입하려면 하위 요소의 `slot` 속성을 사용하여 슬롯 이름을 지정하세요. 컴포넌트의 다른 모든 하위 요소는 기본(이름이 지정되지 않은) `<slot />`에 삽입됩니다.

```astro /slot=".*?"/
---
// src/pages/fred.astro
import Wrapper from '../components/Wrapper.astro';
---

<Wrapper title="Fred의 페이지">
  <img src="https://my.photo/fred.jpg" slot="after-header" />
  <h2>Fred의 모든 것</h2>
  <p>다음은 Fred에 관한 내용입니다.</p>
  <p slot="after-footer">Copyright 2023</p>
</Wrapper>
```

:::tip
컴포넌트의 일치하는 `<slot name="my-slot" />`에 전달하려는 하위 요소에 `slot="my-slot"` 속성을 사용하세요.
:::

래핑 `<div>` 없이 여러 HTML 요소를 컴포넌트의 `<slot/>`에 전달하려면 [Astro의 `<Fragment/>` 컴포넌트](/ko/reference/api-reference/#fragment-)에 `slot=""` 속성을 사용하세요.

```astro title="src/components/CustomTable.astro" "<slot name="header"/>" "<slot name="body"/>"
---
// header 및 body 콘텐츠에 대한 명명된 슬롯이 있는 사용자 정의 테이블 생성
---

<table class="bg-white">
  <thead class="sticky top-0 bg-white"><slot name="header" /></thead>
  <tbody class="[&_tr:nth-child(odd)]:bg-gray-100"><slot name="body" /></tbody>
</table>
```

`slot=""` 속성을 사용하여 `"header"` 및 `"body"` 콘텐츠를 지정하는 HTML 콘텐츠의 여러 행과 열을 삽입합니다. 개별 HTML 요소에도 스타일을 지정할 수 있습니다.

```astro title="src/components/StockTable.astro" {5-7, 9-13} '<Fragment slot="header">' '<Fragment slot="body">'
---
import CustomTable from './CustomTable.astro';
---

<CustomTable>
  <Fragment slot="header">
    <!-- 테이블 헤더 전달 -->
    <tr><th>Product name</th><th>Stock units</th></tr>
  </Fragment>

  <Fragment slot="body">
    <!-- 테이블 바디 전달 -->
    <tr><td>Flip-flops</td><td>64</td></tr>
    <tr><td>Boots</td><td>32</td></tr>
    <tr><td>Sneakers</td><td class="text-red-500">0</td></tr>
  </Fragment>
</CustomTable>
```

명명된 슬롯은 컴포넌트의 직계 하위 요소여야 합니다. 중첩된 요소를 통해 명명된 슬롯을 전달할 수 없습니다.

:::tip
명명된 슬롯에 [UI 프레임워크 컴포넌트](/ko/guides/framework-components/)를 전달할 수도 있습니다!
:::

:::note
Astro 슬롯 이름을 동적으로 생성하는 기능 (예를 들어 map 함수)이 Astro v4.2.0에 추가되었습니다. 이전 버전의 Astro의 경우 프레임워크 자체에서 이러한 동적 슬롯을 생성하는 것이 가장 좋을 수 있습니다.

map 함수에서와 같이 Astro 슬롯 이름을 동적으로 생성하는 것은 불가능합니다. UI 프레임워크 컴포넌트에서 이 기능이 필요한 경우 프레임워크 자체에서 이러한 동적 슬롯을 생성하는 것이 가장 좋습니다.
:::

### 슬롯 대체 콘텐츠

슬롯은 **대체 콘텐츠**를 렌더링할 수도 있습니다. 슬롯과 일치하는 하위 요소가 전달되지 않으면 `<slot />` 요소는 자신의 하위 항목을 렌더링합니다.

```astro {14}
---
// src/components/Wrapper.astro
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props;
---

<div id="content-wrapper">
  <Header />
  <Logo />
  <h1>{title}</h1>
  <slot>
    <p>이것은 슬롯에 전달된 하위 요소가 없는 경우 렌더링 될 대체 콘텐츠입니다.</p>
  </slot>
  <Footer />
</div>
```

### 슬롯 전송

슬롯은 다른 컴포넌트로 전송될 수 있습니다. 예를 들어 중첩된 레이아웃을 생성하는 경우:

```astro title="src/layouts/BaseLayout.astro" {9,12}
---

---

<html lang="ko">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content={Astro.generator} />
    <slot name="head" />
  </head>
  <body>
    <slot />
  </body>
</html>
```

```astro {6,7}
// src/layouts/HomeLayout.astro

 import BaseLayout from "./BaseLayout.astro";
<BaseLayout>
  <slot name="head" slot="head" />
  <slot />
</BaseLayout>
```

:::note
명명된 슬롯은 `<slot />` 태그의 `name` 및 `slot` 속성을 모두 사용하여 다른 컴포넌트로 전송될 수 있습니다.
:::

이제 `HomeLayout`에 전달된 기본 슬롯과 `head` 슬롯은 `BaseLayout`의 슬롯으로 전송됩니다.

```astro
// src/pages/index.astro

 import HomeLayout from "../layouts/HomeLayout.astro";

<HomeLayout>
  <title slot="head">Astro</title>
  <h1>Astro</h1>
</HomeLayout>
```

## HTML 컴포넌트

Astro는 `.html` 파일을 컴포넌트로 가져와 사용하거나 이러한 파일을 `src/pages/` 디렉터리에 페이지로 배치하는 것을 지원합니다. 프레임워크 없이 구축된 기존 사이트의 코드를 재사용하거나 컴포넌트에 동적 기능이 없는지 확인하려는 경우 HTML 컴포넌트를 사용할 수 있습니다.

HTML 컴포넌트에는 유효한 HTML만 포함되어야 하므로 Astro 컴포넌트의 주요 기능이 제공되지 않습니다.

- 프런트매터, 서버 측 가져오기, 동적 표현을 지원하지 않습니다.
- 모든 `<script>` 태그는 번들링되지 않은 상태로 남아 `is:inline`이 있는 것처럼 처리됩니다.
- [`public/` 폴더에 있는 자산만 참조](/ko/basics/project-structure/#public) 할 수 있습니다.

:::note
HTML 컴포넌트의 [`<slot />` 요소](/ko/basics/astro-components/#슬롯)는 Astro 컴포넌트에 있는 것 처럼 동작합니다. 대신 [HTML 웹 컴포넌트 슬롯](https://developer.mozilla.org/ko/docs/Web/HTML/Element/slot) 요소를 사용하려면 `<slot>` 요소에 `is:inline`을 추가하세요.
:::

## 다음 단계

import ReadMore from '~/components/ReadMore.astro';

<ReadMore>
  Astro 프로젝트에서 [UI 프레임워크 컴포넌트](/ko/guides/framework-components/)를 사용하는 방법에
  대해 자세히 알아보세요.
</ReadMore>
